//
// winter - Direct2D GUI framework.
// Copyright (C) 2009 Aleksandar Dezelin 
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//

#ifndef SCOPED_PTR_H
#define SCOPED_PTR_H

#pragma once
#include "winter_assert.h"

namespace winter {
namespace services {

template<class T> class scoped_ptr {
private: 
  T* _px;

  scoped_ptr(scoped_ptr const&);
  scoped_ptr& operator=(scoped_ptr const&);

  typedef scoped_ptr<T> this_type;

  bool operator==(scoped_ptr const&) const;
  bool operator!=(scoped_ptr const&) const;

public:
  typedef T element_type;

  explicit scoped_ptr(T* p = 0): _px(p) {}
  explicit scoped_ptr(std::auto_ptr<T> p): _px(p.release()) {}
  
  ~scoped_ptr() { 
    delete _px; 
  }

  void reset(T* p = 0) {
    WINTER_ASSERT(p == 0 || p != _px); // catch self-reset errors
    this_type(p).swap(*this);
  }

  T* get() const {
    return _px;
  }

  T& operator*() const {
    WINTER_ASSERT(_px != 0);
    return *_px;
  }

  T* operator->() const {
    WINTER_ASSERT(_px != 0);
    return _px;
  }

  operator bool() const {
    return _px != 0;
  }

  void swap(scoped_ptr& b) {
    T* tmp = b._px;
    b._px = _px;
    _px = tmp;
  }
};

template<class T> 
inline void swap(scoped_ptr<T>& a, scoped_ptr<T>& b) {
  a.swap(b);
}

// get_pointer(p) is a generic way to say p.get()
template<class T> 
inline T* get_pointer(scoped_ptr<T> const& p) {
  return p.get();
}

}
}

#endif // SCOPED_PTR_H
